﻿using System;
using System.Collections.Generic;
using NRFramework;
using UnityEngine;
using UnityEngine.UI;

namespace Gp.Scripts.Core
{
    public class GUIRoot : UIRoot
    {
        private Camera _uiCamera;

        private Canvas _rootCanvas;

        private RectTransform _canvasPanel;

        private List<UIPanel> _mFocusingPanels;
        private List<UIPanel> _mTempNewFocusingPanels;

        // public static GUIRoot Instance { get; private set; }

        public override Canvas UIRootCanvas => _rootCanvas;
        public override Camera UICamera => _uiCamera;

        public static readonly Dictionary<string, UIViewBehaviour> UIPool = new();


        public void Init(Camera uiCamera, Canvas canvas)
        {
            _uiCamera               = uiCamera;
            _rootCanvas             = canvas;
            _mFocusingPanels        = new List<UIPanel>();
            _mTempNewFocusingPanels = new List<UIPanel>();
            _rootCanvas.transform.SetParent(transform, false);
        }


        [Obsolete("Panel Should not be Created by Manually. Use GUIManager instead")]
        public override T CreatePanel<T>(string panelId, string prefabPath, int sortingOrder)
        {
            Debug.Assert(!PanelDict.ContainsKey(panelId));
            Debug.Assert(sortingOrder >= startOrder && sortingOrder <= endOrder);

            T panel = Activator.CreateInstance(typeof(T)) as T;
            panel.Create(panelId, this, prefabPath);
            panel.SetSortingOrder(sortingOrder);
            int siblingIndex = GetCurrentSiblingIndex(sortingOrder);
            panel.SetSiblingIndex(siblingIndex);
            PanelDict.Add(panel.panelId, panel);
            SetBackgroundAndFocus();

            return panel;
        }


        public UIPanel CreatePanelSoftly(Type panelType, string panelId, UIPanelBehaviour uiPanelBehaviour)
        {
            Debug.Assert(panelType.IsAssignableFrom(typeof(UIPanel)));
            var panel = Activator.CreateInstance(panelType) as UIPanel;
            panel!.CreateSoftly(panelId, uiPanelBehaviour, this);

            var sortingOrder = GetIncrementedSortingOrder();
            panel.SetSortingOrder(sortingOrder);
            int siblingIndex = GetCurrentSiblingIndex(sortingOrder);
            panel.SetSiblingIndex(siblingIndex);
            PanelDict.Add(panel.panelId, panel);
            SetBackgroundAndFocus();
            return panel;
        }

        private UIPanel CreatePanel(Type panelType, string panelId, string prefabPath, int sortingOrder)
        {
            Debug.Assert(!PanelDict.ContainsKey(panelId));
            Debug.Assert(sortingOrder >= startOrder && sortingOrder <= endOrder);

            UIPanel panel = Activator.CreateInstance(panelType) as UIPanel;
            panel.Create(panelId, this, prefabPath);
            panel.SetSortingOrder(sortingOrder);
            int siblingIndex = GetCurrentSiblingIndex(sortingOrder);
            panel.SetSiblingIndex(siblingIndex);
            PanelDict.Add(panel.panelId, panel);
            SetBackgroundAndFocus();

            return panel;
        }

        public UIPanel CreatePanel(Type panelType, string panelId, string prefabPath)
        {
            return CreatePanel(panelType, panelId, prefabPath, GetIncrementedSortingOrder());
        }


        public override void ClosePanel(string panelId, Action onFinish = null)
        {
            Debug.Assert(PanelDict.ContainsKey(panelId));
            UIPanel panel = PanelDict[panelId];
            PanelDict.Remove(panelId);

            var    obj      = panel.gameObject;
            Action callback = () => obj.SetActive(false);
            callback += onFinish;
            panel.Close(callback);

            UIPool.Add(panelId, panel.viewBehaviour);

            SetBackgroundAndFocus();
        }


        public void ClosePanelImmediately(string panelId)
        {
            Debug.Assert(PanelDict.ContainsKey(panelId));
            UIPanel panel = PanelDict[panelId];
            PanelDict.Remove(panelId);

            var obj = panel.gameObject;
#pragma warning disable CS0618 // Type or member is obsolete
            panel.GUIRemove();
#pragma warning restore CS0618 // Type or member is obsolete

            UIPool.Add(panelId, panel.viewBehaviour);
            obj.SetActive(false);
            SetBackgroundAndFocus();
        }


        public override void SetPanelVisible(string panelId, bool visible)
        {
            Debug.Assert(PanelDict.ContainsKey(panelId));
            UIPanel panel = PanelDict[panelId];
            panel.SetVisible(visible);
            SetBackgroundAndFocus();
        }

        protected override int GetCurrentSiblingIndex(int sortingOrder)
        {
            List<UIPanel> panels = FilterPanels(panel => sortingOrder > panel.canvas.sortingOrder);
            return panels.Count;
        }

        public List<UIPanel> FilterPanels(Func<UIPanel, bool> filterFunc = null)
        {
            List<UIPanel> panels = new List<UIPanel>();
            foreach (KeyValuePair<string, UIPanel> kvPair2 in PanelDict)
            {
                if (filterFunc == null || filterFunc(kvPair2.Value))
                {
                    panels.Add(kvPair2.Value);
                }
            }

            return panels;
        }


        public List<UIPanel> GetFocusingPanels()
        {
            List<UIPanel> vaildPanels = new List<UIPanel>();
            foreach (UIPanel panel in _mFocusingPanels)
            {
                if (panel != null)
                {
                    vaildPanels.Add(panel);
                }
            }

            return vaildPanels;
        }


        internal void SetBackgroundAndFocus()
        {
            List<UIPanel> panels = FilterPanels((panel) => panel.showState != UIPanelShowState.Hidden);
            panels.Sort((a, b) => { return a.canvas.sortingOrder - b.canvas.sortingOrder; });

            UIPanel needBgPanel          = null;
            bool    collectFocusCanBreak = false;

            for (int i = panels.Count - 1; i >= 0; i--)
            {
                UIPanel panel = panels[i];

                if (needBgPanel == null && panel.panelBehaviour.hasBg)
                {
                    needBgPanel = panel;
                }

                if (panel.panelBehaviour.getFocusType == UIPanelGetFocusType.GetWithOthers)
                {
                    _mTempNewFocusingPanels.Add(panel);
                }
                else if (panel.panelBehaviour.getFocusType == UIPanelGetFocusType.Get)
                {
                    _mTempNewFocusingPanels.Add(panel);
                    collectFocusCanBreak = true;
                }

                if (needBgPanel != null && collectFocusCanBreak)
                {
                    break;
                }
            }

            //设置/移除背景
            if (needBgPanel != null)
            {
                needBgPanel.SetBackground();
            }
            else
            {
                UIBlocker.Instance.Unbind();
            }

            //丢失焦点时，由顶至下
            for (int i = _mFocusingPanels.Count - 1; i >= 0; i--)
            {
                UIPanel panel = _mFocusingPanels[i];
                if (panel.panelId != null && !_mTempNewFocusingPanels.Contains(panel))
                {
                    panel.SetFocus(false);
                }
            }

            //获得焦点时，由底至上
            for (int i = 0; i < _mTempNewFocusingPanels.Count; i++)
            {
                UIPanel panel = _mTempNewFocusingPanels[i];
                if (!_mFocusingPanels.Contains(panel))
                {
                    panel.SetFocus(true);
                }
            }

            List<UIPanel> t = _mFocusingPanels;
            _mFocusingPanels        = _mTempNewFocusingPanels;
            _mTempNewFocusingPanels = t;
            _mTempNewFocusingPanels.Clear();
            t = null;
        }
    }
}